# -*- coding: utf-8 -*-
import time
import json
import logging
from hashlib import sha1

import falcon
import redis
import ldap

from auth import authutils
from auth.logger import init_app

api = application = falcon.API()

REDIS_HOST = '127.0.0.1'
REDIS_PORT = 6500
REDIS_PASS = None
REDIS_DB = 15

LDAP_HOST = 'ldap://10.11.50.65:389'
LDAP_USER = 'tp_sys_game_gamecloud'
LDAP_PASSWORD = '1qaz9ol.'

LOGGER = logging.getLogger('auth')
init_app(LOGGER)


class Authorization(object):

    @staticmethod
    def spawn_token(*seeds):
        seeds_str = ','.join(map(str, seeds))
        return sha1(seeds_str).hexdigest()

    @staticmethod
    def save_token(token_id, _ttl=24*3600, **seeds):
        global REDIS_HOST, REDIS_PASS, REDIS_PORT

        redis_auth = {
            'host': REDIS_HOST,
            'port': REDIS_PORT,
            'db': REDIS_DB,
        }
        if REDIS_PASS:
            redis_auth.update(password=REDIS_PASS)

        r = redis.Redis(**redis_auth)
        pipe = r.pipeline()
        pipe.hmset(token_id, seeds)
        pipe.expire(token_id, _ttl)
        pipe.execute()

    @staticmethod
    def get_user_profile_from_ldap(ldapauth, username):
        LDAP_HOST, LDAP_USER, LDAP_PASSWORD = ldapauth
        if not LDAP_USER or not LDAP_PASSWORD:
            return 1, 'LDAP missing user/password!'

        # return False
        ldap.protocol_version = 3
        ldap.set_option(ldap.OPT_REFERRALS, 0)
        conn = ldap.initialize(LDAP_HOST)
        try:
            conn.simple_bind_s('%s' % LDAP_USER, LDAP_PASSWORD)
            baseDN = 'dc=iqiyi,dc=pps'
            searchScope = ldap.SCOPE_SUBTREE
            searchFilter = '(&(objectClass=user)(sAMAccountName='+username+'))'

            ldap_result_id = conn.search(baseDN, searchScope, searchFilter, None)
            result_type, result_data = conn.result(ldap_result_id, 0)
            LOGGER.debug('LDAP result: %r!', result_data)

            if result_type == ldap.RES_SEARCH_ENTRY:
                data = result_data[0][1]
                show_name = data['name'][0].decode('utf-8')
                email = data['mail'][0]
                resp_data = {'show_name': show_name, 'email': email}

                return 0, resp_data
            else:
                return 1, 'not found'
        except ldap.LDAPError, e:
            LOGGER.exception(e.message)
            return 1, str(e)

    def on_get(self, req, resp):
        global LDAP_HOST, LDAP_USER, LDAP_PASSWORD
        # Header
        client_ip = req.get_header('x_real_ip')

        # Param
        user_name = req.get_param('user_name', required=True)

        #Ldap config
        ldap_auth = (LDAP_HOST, LDAP_USER, LDAP_PASSWORD)

        #Get User form DB.
        s, resp_data = authutils._get_user_profile(user_name)
        if s:
            data = {
                'status': s,
                'msg': 'fail',
                'data': 'From DB: %s' % resp_data,
            }
            LOGGER.error('Get user_profile from DB error: %s' % resp_data)
        elif len(resp_data)>0:
            new_token = self.spawn_token(time.time())
            self.save_token(new_token, client_ip=client_ip, user_name=user_name)
            data = {
                'status': s,
                'msg': 'success from db',
                'data': {
                    'token': new_token,
                }
            }
            LOGGER.info('Get user_profile from DB success: %s' % resp_data)
        else:
            s, retval = self.get_user_profile_from_ldap(ldap_auth, user_name)
            if s:
                data = {
                    'status': s,
                    'msg': 'fail',
                    'data': 'From LDAP: %s!' % retval,
                }
                LOGGER.error('Get user_profile from LDAP fail : %s' % resp_data)
            else:
                email = retval['email']
                show_name = retval['show_name'].encode("utf-8")
                new_token = self.spawn_token(time.time())
                self.save_token(new_token, client_ip=client_ip, user_name=user_name)
                s, m = authutils.register_user(user_name, show_name, email)
                if s:
                    data = {
                        'status': s,
                        'msg': 'fail',
                        'data': m,
                    }
                else:
                    data = {
                        'status': 0,
                        'msg': 'success from ldap',
                        'data': {
                            # 'token': user_name,
                            # 'client_ip': req.get_header('x_real_ip'),
                            'token': new_token,
                        }
                    }
                LOGGER.info('Get user_profile from LDAP success :%s' % resp_data)
        resp.body = json.dumps(data)


class Tokens(object):

    @staticmethod
    def get_token(token_id):
        redis_auth = {
            'host': REDIS_HOST,
            'port': REDIS_PORT,
            'db': REDIS_DB,
        }
        if REDIS_PASS:
            redis_auth.update(password=REDIS_PASS)
        r = redis.Redis(**redis_auth)
        return r.hgetall(token_id)

    @staticmethod
    def check_token(token, remote_ip):
        return token['client_ip'] == remote_ip

    def on_get(self, req, resp, token_id):
        # Header
        x_ip = req.get_header('x_real_ip')

        token = self.get_token(token_id)
        if not token:
            data = {
                'status': 404,
                'msg': 'fail',
                'data': 'token not found!',
            }
            resp.body = json.dumps(data)
            return

        if self.check_token(token, x_ip):
            data = {
                'status': 0,
                'msg': 'success',
                'data': {
                    'user_name': token['user_name'],
                },
            }
        else:
            data = {
                'status': 1,
                'msg': 'fail',
                'data': 'Invalid token',
            }
        resp.body = json.dumps(data)


api.add_route('/authorization', Authorization())
api.add_route('/tokens/{token_id}', Tokens())
